package se.sll.itintegration.catalogue.gui.camel.cdi;

import java.util.Collections;
import java.util.List;

import org.apache.camel.Exchange;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.model.dataformat.JsonLibrary;
import org.apache.camel.processor.aggregate.GroupedExchangeAggregationStrategy;

import se.sll.itintegration.catalogue.camel.processor.IdmapProcessor;
import se.sll.itintegration.catalogue.camel.processor.OfferProcessor;
import se.sll.itintegration.catalogue.camel.processor.ProductProcessor;
import se.sll.itintegration.catalogue.gui.service.view.ViewBaseProcessor;
import se.sll.itintegration.catalogue.gui.service.view.capacity.CapacityCreateRequestListTranslator;
import se.sll.itintegration.catalogue.gui.service.view.capacity.CapacityProcessor;
import se.sll.itintegration.catalogue.gui.service.view.capacity.CapacityViewProcessor;
import se.sll.itintegration.catalogue.gui.service.view.capacity.CapacityViewUnitListTranslator;
import se.sll.itintegration.catalogue.gui.service.view.capacity.UnitListTranslator;
import se.sll.itintegration.catalogue.gui.service.view.users.UserListTranslator;
import se.sll.itintegration.catalogue.gui.service.view.users.UserViewProcessor;
import se.sll.itintegration.catalogue.gui.service.view.users.UsersViewProcessor;
import se.sll.service.catalogue.common.data.UnitList;
import se.sll.service.catalogue.common.property.CatalogProperties;
import se.sll.service.catalogue.common.rest.request.CapacityCreateRequest;
import se.sll.service.catalogue.gui.api.model.UnitNameList;

/**
 *
 * @author khaleddaham
 */
public class CamelRoute extends RouteBuilder {

    public static final String GET_OFFER_ALL = "direct:offers";
    public static final String GET_OFFER_VIEW = "direct:get:offerview";
    public static final String GET_ONE_OFFER_VIEW = "direct:get:oneofferview";
    public static final String FROM_ONEOFFER = "direct:oneoffer";
    public static final String FROM_OFFERS_BYUNITIDS = "direct:offers:byunitids";

    public static final String FROM_IDMAP = "direct:idmap";
    public static final String GET_IDMAP_VIEW = "direct:get:idmapview";

    public static final String GET_PRODUCT_VIEW = "direct:get:productview";
    public static final String GET_PRODUCT_ALL_LIST = "direct:get:product:list";
    public static final String FROM_PRODUCTREAD = "direct:productread";
    public static final String GET_PRODUCT_ALL = "direct:product";

    public static final String GET_CODESYSTEM_ALL = "direct:codesystem";
    public static final String GET_CODE_ALL = "direct:code";
    
    public static final String GET_USER_ALL = "direct:user";
    public static final String GET_USERS_VIEW = "direct:usersView";
    public static final String GET_PROFILE_VIEW = "direct:user:view";
    
    public static final String FROM_CAPACITY_BYUNITIDS = "direct:capacity:byunitids";
    public static final String FROM_CAPACITY = "direct:capacity";
    public static final String GET_CAPACITY_VIEW = "direct:capacityView";
    public static final String UPDATE_CAPACITY_VIEW = "direct:updateCapacityView";
    private static final String UPDATE_CAPACITY_VIEW_UPDATE = "direct:updateCapacityViewUpdate";
    private static final String UPDATE_CAPACITY_VIEW_READBACK = "direct:updateCapacityViewReadback";
    private static final String FROM_CAPACITY_VIEW_OFFERS = "direct:capacityViewOffers";
    private static final String FROM_CAPACITY_VIEW_OFFERS_ALL = "direct:capacityViewOffersAll";
    private static final String FROM_CAPACITY_VIEW_CAPACITY = "direct:capacityViewCapacity";
    private static final String FROM_CAPACITY_VIEW_CAPACITY_ALL = "direct:capacityViewCapacityAll";

//    private static final String LOG_SHOW_ALL = "log:log?showAll=true&multiline=true";

    @Override
    public void configure() throws Exception {
        from(FROM_PRODUCTREAD)
                .routeId(routeIdFromName(FROM_PRODUCTREAD))
                .setHeader(Exchange.HTTP_METHOD, constant("GET"))
                .setHeader(Exchange.CONTENT_TYPE, constant("application/json; charset=UTF-8"))
                .setHeader(Exchange.ACCEPT_CONTENT_TYPE, constant("application/json; charset=UTF-8"))
                .setHeader(Exchange.HTTP_URI, simple(CatalogProperties.getProperty(CatalogProperties.NAME.PRODUCT_BASE_URL) + "/products/"))
                .setBody(constant(null))
                .to("log:productread?showAll=true&multiline=true")
                .to("http4://product/products")
                .to("log:http?showAll=true&multiline=true")
                .bean(ProductProcessor.getInstance(), "productResponseJSON")
                .to("log:done?showAll=true&multiline=true");

        from(GET_OFFER_ALL)
                .routeId(routeIdFromName(GET_OFFER_ALL))
                .setHeader(Exchange.HTTP_URI, simple(CatalogProperties.getProperty(CatalogProperties.NAME.OFFERS_BASE_URL) + "/units/"))
                .setHeader(Exchange.HTTP_METHOD, constant("GET"))
                .setHeader(Exchange.CONTENT_TYPE, constant("application/json; charset=UTF-8"))
                .setHeader(Exchange.ACCEPT_CONTENT_TYPE, constant("application/json; charset=UTF-8"))
                .to("http4://offers/path")
                .bean(OfferProcessor.getInstance(), "offerResponseJSON");

        from(GET_CODE_ALL)
                .routeId(routeIdFromName(GET_CODE_ALL))
                .setHeader(Exchange.HTTP_METHOD, constant("GET"))
                .setHeader(Exchange.CONTENT_TYPE, constant("application/json; charset=UTF-8"))
                .setHeader(Exchange.ACCEPT_CONTENT_TYPE, constant("application/json; charset=UTF-8"))
                .setHeader(Exchange.HTTP_URI, constant(CatalogProperties.getProperty(CatalogProperties.NAME.PRODUCT_BASE_URL) + "/codesystems/codes"))
                .to("http4://product")
                .bean(ProductProcessor.getInstance(), "translateToCodeMap");

        from(GET_CODESYSTEM_ALL)
                .routeId(routeIdFromName(GET_CODESYSTEM_ALL))
                .setHeader(Exchange.HTTP_METHOD, constant("GET"))
                .setHeader(Exchange.CONTENT_TYPE, constant("application/json; charset=UTF-8"))
                .setHeader(Exchange.ACCEPT_CONTENT_TYPE, constant("application/json; charset=UTF-8"))
                .setHeader(Exchange.HTTP_URI, constant(CatalogProperties.getProperty(CatalogProperties.NAME.PRODUCT_BASE_URL) + "/codesystems/"))
                .to("http4://product")
                .bean(ProductProcessor.getInstance(), "translateToCodeSystemMap");

        from(GET_PRODUCT_ALL_LIST)
                .routeId(routeIdFromName(GET_PRODUCT_ALL_LIST))
                .setHeader(Exchange.HTTP_METHOD, constant("GET"))
                .setHeader(Exchange.CONTENT_TYPE, constant("application/json; charset=UTF-8"))
                .setHeader(Exchange.ACCEPT_CONTENT_TYPE, constant("application/json; charset=UTF-8"))
                .setHeader(Exchange.HTTP_URI, constant(CatalogProperties.getProperty(CatalogProperties.NAME.PRODUCT_BASE_URL) + "/products"))
                .to("http4://product")
                .bean(ProductProcessor.getInstance(), "translateToProtuctList");

        from(GET_PRODUCT_ALL)
                .routeId(routeIdFromName(GET_PRODUCT_ALL))
                .setHeader(Exchange.HTTP_METHOD, constant("GET"))
                .setHeader(Exchange.CONTENT_TYPE, constant("application/json; charset=UTF-8"))
                .setHeader(Exchange.ACCEPT_CONTENT_TYPE, constant("application/json; charset=UTF-8"))
                .setHeader(Exchange.HTTP_URI, constant(CatalogProperties.getProperty(CatalogProperties.NAME.PRODUCT_BASE_URL) + "/products"))
                .to("http4://product")
                .bean(ProductProcessor.getInstance(), "productResponseJSON");

        from(GET_USER_ALL)
                .routeId(routeIdFromName(GET_USER_ALL))
                .to("ejb:java:global/gui-1.0-SNAPSHOT/UserEjb?method=findAll")
                .bean(UserListTranslator.getInstance(), "translate");
  
        from(FROM_OFFERS_BYUNITIDS)
                .routeId(routeIdFromName(FROM_OFFERS_BYUNITIDS))
                .setHeader(Exchange.HTTP_METHOD, constant("POST"))
                .setHeader(Exchange.CONTENT_TYPE, constant("application/json; charset=UTF-8"))
                .setHeader(Exchange.ACCEPT_CONTENT_TYPE, constant("application/json; charset=UTF-8"))
                .setHeader(Exchange.HTTP_URI, constant(CatalogProperties.getProperty(CatalogProperties.NAME.OFFERS_BASE_URL) + "/units/byunitids"))
                .to("log:byunitids?showAll=true&multiline=true")
                .marshal().json(JsonLibrary.Jackson, UnitNameList.class)
                .to("http4://offers/units/byunitids")
                .to("log:afterjetty?showAll=true&multiline=true")
                .bean(OfferProcessor.getInstance(), "offerResponseJSON")
                .to("log:done?showAll=true&multiline=true");

        from(FROM_CAPACITY_BYUNITIDS)
                .routeId(routeIdFromName(FROM_CAPACITY_BYUNITIDS))
                .setHeader(Exchange.HTTP_METHOD, constant("POST"))
                .setHeader(Exchange.CONTENT_TYPE, constant("application/json; charset=UTF-8"))
                .setHeader(Exchange.ACCEPT_CONTENT_TYPE, constant("application/json; charset=UTF-8"))
                .setHeader(Exchange.HTTP_URI, constant(CatalogProperties.getProperty(CatalogProperties.NAME.CAPACITY_BASE_URL) + "/capacity/byunitids"))
                .to("log:byunitids?showAll=true&multiline=true")
                .marshal().json(JsonLibrary.Jackson, UnitList.class)
                .to("http4://capacity/capacity/byunitids")
                .bean(new CapacityProcessor(), "capacityResponseJSON")
                .to("log:done?showAll=true&multiline=true");

        from(FROM_CAPACITY)
                .routeId(routeIdFromName(FROM_CAPACITY))
                .setHeader(Exchange.HTTP_METHOD, constant("GET"))
                .setHeader(Exchange.CONTENT_TYPE, constant("application/json; charset=UTF-8"))
                .setHeader(Exchange.ACCEPT_CONTENT_TYPE, constant("application/json; charset=UTF-8"))
                .setHeader(Exchange.HTTP_URI, constant(CatalogProperties.getProperty(CatalogProperties.NAME.CAPACITY_BASE_URL) + "/capacity/"))
                .to("http4://capacity/capacity")
                .bean(new CapacityProcessor(), "capacityResponseJSON");

        from(GET_USERS_VIEW)
                .routeId(routeIdFromName(GET_USERS_VIEW))
                .bean(new UsersViewProcessor(), "create")
                // Init ViewBase fields
                .bean(new ViewBaseProcessor(), "init")
                // Units
                .setHeader(Exchange.HTTP_METHOD, constant("GET"))
                .setHeader(Exchange.ACCEPT_CONTENT_TYPE, constant("application/json; charset=UTF-8"))
                .setHeader(Exchange.HTTP_URI, constant(CatalogProperties.getProperty(CatalogProperties.NAME.OFFERS_BASE_URL) + "/units/"))
                .to("http4://offers/units")
                .bean(OfferProcessor.getInstance(), "offerResponseJSON")
                .bean(OfferProcessor.getInstance(), "unitsToUnitReferences")
                .bean(new UsersViewProcessor(), "setUnits")
                // Users
                .to("ejb:java:module/UserEjb?method=findAll")
                .bean(UserListTranslator.getInstance(), "translate")
                .bean(new UsersViewProcessor(), "setUsers")
                // Output
                .bean(new UsersViewProcessor(), "output");
        
        from(GET_PROFILE_VIEW)
            .routeId(routeIdFromName(GET_PROFILE_VIEW))
            .bean(new UserViewProcessor(), "create")
            .bean(new ViewBaseProcessor(), "init")
            .to("ejb:java:module/UserEjb?method=findByUserName(${property.sc.userPrincipal.name})")
            .bean(UserListTranslator.getInstance(), "translate")
            .bean(new UserViewProcessor(), "setUser")
            .bean(new UserViewProcessor(), "output");

        from(FROM_ONEOFFER)
                .routeId(routeIdFromName(FROM_ONEOFFER))
                .setHeader(Exchange.HTTP_URI, simple(CatalogProperties.getProperty(CatalogProperties.NAME.OFFERS_BASE_URL) + "/units/${header.hsaId}"))
                .setHeader(Exchange.HTTP_METHOD, constant("GET"))
                .setHeader(Exchange.CONTENT_TYPE, constant("application/json; charset=UTF-8"))
                .setHeader(Exchange.ACCEPT_CONTENT_TYPE, constant("application/json; charset=UTF-8"))
                .to("http4://offers/units/hsaId")
                .bean(OfferProcessor.getInstance(), "offerResponseJSON");  

        from(GET_ONE_OFFER_VIEW)
            .routeId(routeIdFromName(GET_ONE_OFFER_VIEW))
            .setHeader(Exchange.HTTP_URI, simple(CatalogProperties.getProperty(CatalogProperties.NAME.OFFERS_BASE_URL) + "/units/${header.hsaId}"))
            .bean(OfferProcessor.getInstance(), "createView")
                .multicast(new GroupedExchangeAggregationStrategy()).parallelProcessing()
                .to(FROM_ONEOFFER, GET_PRODUCT_ALL)
                .end()
            .bean(OfferProcessor.getInstance(), "mergeToOneOfferView");  
        
        // Fetch data from Offer and populate an OfferView object
        from(GET_OFFER_VIEW)
                .routeId(routeIdFromName(GET_OFFER_VIEW))
                .bean(OfferProcessor.getInstance(), "createView")
                .bean(new ViewBaseProcessor(), "init")
                .multicast(new GroupedExchangeAggregationStrategy()).parallelProcessing()
                    .to(GET_OFFER_ALL, GET_PRODUCT_ALL, GET_USER_ALL)
                .end()
                .bean(OfferProcessor.getInstance(), "mergeToOfferView");
        
        // Fetch data from Product and populate an ProductView object
        // Fetch all products and its code relations, all codesystems, all codes
        from(GET_PRODUCT_VIEW)
                .routeId(routeIdFromName(GET_PRODUCT_VIEW))
                .bean(ProductProcessor.getInstance(), "createView")
                .bean(new ViewBaseProcessor(), "init")
                .multicast(new GroupedExchangeAggregationStrategy()).parallelProcessing()
                    .to(GET_PRODUCT_ALL_LIST, GET_CODESYSTEM_ALL)
                .end()
                .bean(ProductProcessor.getInstance(), "mergeToProductView");

        // Fetch data from Idmap and populate an IdmapView object
        from(GET_IDMAP_VIEW)
                .routeId(routeIdFromName(GET_IDMAP_VIEW))
                .bean(new IdmapProcessor(), "createView")
                .bean(new ViewBaseProcessor(), "init")
                .setHeader(Exchange.HTTP_METHOD, constant("GET"))
                .setHeader(Exchange.CONTENT_TYPE, constant("application/json; charset=UTF-8"))
                .setHeader(Exchange.ACCEPT_CONTENT_TYPE, constant("application/json; charset=UTF-8"))
                .setHeader(Exchange.HTTP_URI, constant(CatalogProperties.getProperty(CatalogProperties.NAME.IDMAP_BASE_URL) + "/"))
                .to("http4://idmap")
                .bean(new IdmapProcessor(), "convertToIdmapView");

        // Returns information needed to render the capacity view
        // Body in: -
        // Body out: CapacityView
        from(GET_CAPACITY_VIEW)
                .routeId(routeIdFromName(GET_CAPACITY_VIEW))
                .bean(CapacityViewProcessor.getInstance(), "create")
                // Init ViewBase fields
                .bean(new ViewBaseProcessor(), "init")
                // Get capacities
                .choice()
                    .when().simple("${property.sc.isUserInRole('SUPERADMIN')}")
                        // SUPERADMIN gets capacities for all units
                        .multicast(new GroupedExchangeAggregationStrategy()).parallelProcessing()
                            .to(FROM_CAPACITY_VIEW_OFFERS_ALL, FROM_PRODUCTREAD, FROM_CAPACITY_VIEW_CAPACITY_ALL)
                        .endChoice()
                        .bean(CapacityViewProcessor.getInstance(), "merge")

                    .when().simple("${property.sc.isUserInRole('CAPACITYADMIN')}")
                        // CAPACITYADMIN gets list of units from user profile
                        .to("ejb:java:module/UserEjb?method=findByUserName(${property.sc.userPrincipal.name})")
                        .setBody().simple("${body[0].careUnits}")
                        .bean(UnitListTranslator.getInstance(), "translate")
                        .choice()
                            .when().simple("${body.empty}")
                                // No units = no capacities
                                .setBody(constant(Collections.EMPTY_LIST))
                            .otherwise()
                                // Get capacities for the user's units
                                .marshal().json(JsonLibrary.Jackson, UnitList.class)
                                .multicast(new GroupedExchangeAggregationStrategy()).parallelProcessing()
                                    .to(FROM_CAPACITY_VIEW_OFFERS, FROM_PRODUCTREAD, FROM_CAPACITY_VIEW_CAPACITY)
                                .endChoice()
                                .bean(CapacityViewProcessor.getInstance(), "merge")
                        .endChoice()

                    .otherwise()
                        // Other roles gets nothing
                        .setBody(constant(Collections.EMPTY_LIST))
                .end()
                .bean(CapacityViewProcessor.getInstance(), "setCapacity")
                // Output
                .setBody().simple("${property.view}");

        // Updates capacities and returns merged updated capacity information
        // Body in: CapacityView
        // Body out: List<CapacityViewUnit>
        from(UPDATE_CAPACITY_VIEW)
                .routeId(routeIdFromName(UPDATE_CAPACITY_VIEW))
                .multicast()
                    .to(UPDATE_CAPACITY_VIEW_UPDATE, UPDATE_CAPACITY_VIEW_READBACK)
                .end();

        // Updates capacities and returns updated capacity information
        // Body in: CapacityView
        // Body out: List<CapacityResponse>
        from(UPDATE_CAPACITY_VIEW_UPDATE)
                .routeId(routeIdFromName(UPDATE_CAPACITY_VIEW_UPDATE))
                .bean(CapacityCreateRequestListTranslator.getInstance(), "translate")
                .split().body(List.class)
                    .marshal().json(JsonLibrary.Jackson, CapacityCreateRequest.class)
                    .setHeader(Exchange.HTTP_METHOD, constant("PUT"))
                    .setHeader(Exchange.CONTENT_TYPE, constant("application/json; charset=UTF-8"))
                    .setHeader(Exchange.ACCEPT_CONTENT_TYPE, constant("application/json; charset=UTF-8"))
                    .setHeader(Exchange.HTTP_URI, constant(CatalogProperties.getProperty(CatalogProperties.NAME.CAPACITY_BASE_URL) + "/capacity"))
                    .to("log:updateCapacity?showAll=true&multiline=true")
                    .to("http4://capacity/capacity")
                    .to("log:afterjetty?showAll=true&multiline=true")
                .end();

        // Retrieves updated capacity information for all units updated by a list of CapacityCreateRequests.
        // Body in: CapacityView
        // Body out: List<Unit>
        from(UPDATE_CAPACITY_VIEW_READBACK)
                .routeId(routeIdFromName(UPDATE_CAPACITY_VIEW_READBACK))
                .bean(CapacityViewUnitListTranslator.getInstance(), "translate")
                .marshal().json(JsonLibrary.Jackson, UnitList.class)
                .multicast(new GroupedExchangeAggregationStrategy()).parallelProcessing()
                    .to(FROM_CAPACITY_VIEW_OFFERS, FROM_PRODUCTREAD, FROM_CAPACITY_VIEW_CAPACITY)
                .end()
                .bean(CapacityViewProcessor.getInstance(), "merge");

        // Retrieves offers for a given list of units
        // Body in: JSON UnitList
        // Body out: List<Unit>
        from(FROM_CAPACITY_VIEW_OFFERS)
                .routeId(routeIdFromName(FROM_CAPACITY_VIEW_OFFERS))
                .setHeader(Exchange.HTTP_METHOD, constant("POST"))
                .setHeader(Exchange.CONTENT_TYPE, constant("application/json; charset=UTF-8"))
                .setHeader(Exchange.ACCEPT_CONTENT_TYPE, constant("application/json; charset=UTF-8"))
                .setHeader(Exchange.HTTP_URI, constant(CatalogProperties.getProperty(CatalogProperties.NAME.OFFERS_BASE_URL) + "/units/byunitids"))
                .to("log:unitsByunitids?showAll=true&multiline=true")
                .to("http4://offers/units/byunitids")
                .to("log:afterjetty?showAll=true&multiline=true")
                .bean(OfferProcessor.getInstance(), "offerResponseJSON")
                .to("log:done?showAll=true&multiline=true");

        // Retrieves all offers
        // Body in: -
        // Body out: List<Unit>
        from(FROM_CAPACITY_VIEW_OFFERS_ALL)
                .routeId(routeIdFromName(FROM_CAPACITY_VIEW_OFFERS_ALL))
                .setHeader(Exchange.HTTP_METHOD, constant("GET"))
                .setHeader(Exchange.CONTENT_TYPE, constant("application/json; charset=UTF-8"))
                .setHeader(Exchange.ACCEPT_CONTENT_TYPE, constant("application/json; charset=UTF-8"))
                .setHeader(Exchange.HTTP_URI, constant(CatalogProperties.getProperty(CatalogProperties.NAME.OFFERS_BASE_URL) + "/units"))
                .to("log:units?showAll=true&multiline=true")
                .to("http4://offers/units")
                .to("log:afterjetty?showAll=true&multiline=true")
                .bean(OfferProcessor.getInstance(), "offerResponseJSON")
                .to("log:done?showAll=true&multiline=true");

        // Retrieves capacities for a given list of units
        // Body in: JSON UnitList
        // Body out: List<CapacityResponse>
        from(FROM_CAPACITY_VIEW_CAPACITY)
                .routeId(routeIdFromName(FROM_CAPACITY_VIEW_CAPACITY))
                .setHeader(Exchange.HTTP_METHOD, constant("POST"))
                .setHeader(Exchange.CONTENT_TYPE, constant("application/json; charset=UTF-8"))
                .setHeader(Exchange.ACCEPT_CONTENT_TYPE, constant("application/json; charset=UTF-8"))
                .setHeader(Exchange.HTTP_URI, constant(CatalogProperties.getProperty(CatalogProperties.NAME.CAPACITY_BASE_URL) + "/capacity/byunitids"))
                .to("log:capacityByunitids?showAll=true&multiline=true")
                .to("http4://capacity/capacity/byunitids")
                .bean(new CapacityProcessor(), "capacityResponseJSON")
                .to("log:done?showAll=true&multiline=true");

        // Retrieves capacities for all units
        // Body in: -
        // Body out: List<CapacityResponse>
        from(FROM_CAPACITY_VIEW_CAPACITY_ALL)
                .routeId(routeIdFromName(FROM_CAPACITY_VIEW_CAPACITY_ALL))
                .setHeader(Exchange.HTTP_METHOD, constant("GET"))
                .setHeader(Exchange.CONTENT_TYPE, constant("application/json; charset=UTF-8"))
                .setHeader(Exchange.ACCEPT_CONTENT_TYPE, constant("application/json; charset=UTF-8"))
                .setHeader(Exchange.HTTP_URI, constant(CatalogProperties.getProperty(CatalogProperties.NAME.CAPACITY_BASE_URL) + "/capacity"))
                .to("log:capacity?showAll=true&multiline=true")
                .to("http4://capacity/capacity")
                .bean(new CapacityProcessor(), "capacityResponseJSON")
                .to("log:done?showAll=true&multiline=true");
    }

    /**
     *
     * @param routeName
     * @return
     */
    private String routeIdFromName(String routeName) {
        return routeName.replaceFirst("^direct:", "");
    }
}
